#encoding:utf-8

"""
参考文档: https://docs.python.org/zh-cn/3/tutorial/classes.html#scopes-and-namespaces-example
Python的作用域和命名空间

命名空间是从一个名字到对象的映射，当前大部分的命名空间都是由Python字典实现的；
但是一般情况下基本不去关注这个（除非涉及到性能问题），这个或许会变化；

命名空间的例子:
    存放内置函数的集合set(包含abs()这样的函数等)；
    模块的全局名称，函数中的局部名称
    对象的属性集合其实也可以看作是一种命名空间的形式

需要注意的是，不同命名空间中的名称之间绝对没有关系，只需要在使用的时候加上模块名称就行

一个作用域是一个命名空间可直接访问的Python程序的区域，“可直接访问”意味着对名称的非限定引用会尝试在命名空间中查找

作用域是静态确定的，但是会被动态使用。在执行期间的任何时刻，会有3到4个可直接访问的嵌套作用域：
    最先搜索的最内部作用域包含局部名称
    从最近的封闭作用域开始搜索的任何封闭函数的作用域，包含非局部名称和非全局名称
    倒数第二个作用域包含当前模块的全局名称
    最外面的作用域（最后搜索）是包含内置名称的命名空间

需要注意的是，我们要小心改变global和nolocal变量，避免产生不必要的影响

global 表面特定变量存在于全局作用域且在其中重新绑定
nonlocal 表明变量存在于外层作用域且应该被重新绑定
"""

# 代码示例
testVarible = u"全局变量"

def testFuncScope():

    # 下面的例子说明如何引用不同作用域和命名空间的例子
    # global 和 nonlocal是如何影响变量绑定的
    
    # 在函数里重新定义一个testVarible
    testVarible = u"Func函数里的局部变量"

    def do_local():
        # 重新定义一个只在当前函数存在的testVarible变量
        testVarible = u"local函数里的变量"
        return testVarible

    def do_nonlocal():
        # 声明当前变量是当前作用域之外的变量，也就是非本函数所有
        nonlocal testVarible
        print("nonlocal testVarible is {}".format(testVarible))

        # 修改一下nonlocal变量
        testVarible = u"我在nonlocal函数里修改了"
        return testVarible
    
    def do_global():
        # 表明当前变量是全局变量
        global testVarible
        print("global testVarible is {}".format(testVarible))

        # 修改全局变量并且返回
        testVarible = u"我在global函数修改了全局变量的值"
        return testVarible

    # 当前函数里的局部变量值
    print("函数里的testVarible is {}".format(testVarible))

    # 调用do_local,并不会改变当前函数里的变量
    do_local()
    print(u"调用do_local函数后，testVarible is {}".format(testVarible))

    # 调用do_nonlocal函数，不会改变全局变量，但是改变了当前函数的变量
    do_nonlocal()
    print(u"调用do_nonlocal函数后，testVarible is {}".format(testVarible))

    # 调用do_global函数，会改变全局变量的值，但是不改变当前函数里的值
    do_global()
    print(u"调用do_global函数后，testVarible is {}".format(testVarible))

testFuncScope()
    
